
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "../mac.h"
#include "aws_iot_client_main.h"

#include "core_mqtt.h"
#include "core_mqtt_state.h"
#include "network_transport.h"
#include "backoff_algorithm.h"

#include "clock.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"

#include "aws_iot_Subscribe.h"
#include "aws_iot_Publish.h"
#include "aws_iot_connect.h"


#define NETWORK_BUFFER_SIZE (1024)
//网络缓冲区必须在 MQTT 上下文的生存期内保持有效。
static uint8_t buffer[NETWORK_BUFFER_SIZE];
MQTTFixedBuffer_t networkBuffer;
TransportInterface_t transport;

static const char *TAG = "AWS IoT客户端";
SemaphoreHandle_t sync_aws_creat;
MQTTContext_t mqttContext;
NetworkContext_t xNetworkContext;


static void eventCallback(MQTTContext_t *pMqttContext, MQTTPacketInfo_t *pPacketInfo, MQTTDeserializedInfo_t *pDeserializedInfo)
{
    uint16_t packetIdentifier;

    packetIdentifier = pDeserializedInfo->packetIdentifier;
    if ((pPacketInfo->type & 0xF0) == MQTT_PACKET_TYPE_PUBLISH)
    {
        handleIncomingPublish(pDeserializedInfo->pPublishInfo, packetIdentifier);
    }
    else
    {
        // ESP_LOGE(TAG,"未处理的数据包类型: %d",pPacketInfo->type);
        switch (pPacketInfo->type)
        {
            case MQTT_PACKET_TYPE_SUBACK:
                /* A SUBACK from the broker, containing the server response to our subscription request, has been received.
                * It contains the status code indicating server approval/rejection for the subscription to the single topic
                * requested. The SUBACK will be parsed to obtain the status code, and this status code will be stored in global
                * variable globalSubAckStatus. */
                updateSubAckStatus(pPacketInfo);

                /* Check status of the subscription request. If globalSubAckStatus does not indicate
                * server refusal of the request (MQTTSubAckFailure), it contains the QoS level granted
                * by the server, indicating a successful subscription attempt. */
                // if (globalSubAckStatus != MQTTSubAckFailure)
                // {
                //     LogInfo(("Subscribed to the topic %.*s. with maximum QoS %u.\n\n",
                //             MQTT_EXAMPLE_TOPIC_LENGTH,
                //             MQTT_EXAMPLE_TOPIC,
                //             globalSubAckStatus));
                // }

                /* Make sure ACK packet identifier matches with Request packet identifier. */
                // assert(globalSubscribePacketIdentifier == packetIdentifier);
                break;
            case MQTT_PACKET_TYPE_UNSUBACK:
                ESP_LOGE(TAG,"Unsubscribed from the topic");
                /* Make sure ACK packet identifier matches with Request packet identifier. */
                // assert(globalUnsubscribePacketIdentifier == packetIdentifier);
                break;
            case MQTT_PACKET_TYPE_PINGRESP:

                /* Nothing to be done from application as library handles
                * PINGRESP. */
                ESP_LOGE(TAG,"PINGRESP should not be handled by the application "
                        "callback when using MQTT_ProcessLoop.\n\n");
                break;
            case MQTT_PACKET_TYPE_PUBACK:
                // ESP_LOGE(TAG,"PUBACK 包ID %u.\n\n", packetIdentifier);
                /* Cleanup publish packet when a PUBACK is received. */
                cleanupOutgoingPublishWithPacketID(packetIdentifier);
                break;
            /* Any other packet type is invalid. */
            default:
                ESP_LOGE(TAG,"Unknown packet type received:(%02x).\n\n", pPacketInfo->type);
        }
    }
}

static int initializeMqtt(MQTTContext_t *pMqttContext, NetworkContext_t *pNetworkContext)
{
    int returnStatus = EXIT_SUCCESS;

    /* Fill in TransportInterface send and receive function pointers.
     * For this demo, TCP sockets are used to send and receive data
     * from network. Network context is SSL context for OpenSSL.*/
    transport.pNetworkContext = pNetworkContext;
    transport.send = espTlsTransportSend;
    transport.recv = espTlsTransportRecv;
    networkBuffer.pBuffer = buffer;
    networkBuffer.size = NETWORK_BUFFER_SIZE;

    MQTTStatus_t mqttStatus = MQTT_Init(pMqttContext, &transport, Clock_GetTimeMs, eventCallback, &networkBuffer);
    if (mqttStatus != MQTTSuccess)
    {
        returnStatus = EXIT_FAILURE;
        ESP_LOGE(TAG,"MQTT库初始化 失败: Status = %s.", MQTT_Status_strerror(mqttStatus));
    }

    return returnStatus;
}

static int aws_iot_client_main(void *param)
{
    int returnStatus = EXIT_SUCCESS;

    sync_aws_creat = xSemaphoreCreateBinary();
    for (;;)
    {
        ESP_LOGE(TAG,"等待触发 AWS IoT初始化...");
        xSemaphoreTake(sync_aws_creat, portMAX_DELAY);

        returnStatus = initializeMqtt(&mqttContext, &xNetworkContext);
        if (returnStatus != EXIT_SUCCESS)
        {
            ESP_LOGE(TAG,"Mqtt 初始化失败,原因(%d)",returnStatus);
        }
        else
        {
            if(wireless_state.station_state == connected) connectToAWS(&mqttContext,&xNetworkContext);
            // vTaskDelay(pdMS_TO_TICKS(500));
            disconnectAWS(&mqttContext,&xNetworkContext);
        }

        ESP_LOGE(TAG,"开始休眠");
        vTaskDelay(pdMS_TO_TICKS(500));
        // sleep(5);
        ESP_LOGE(TAG,"唤醒");
        AWS_ConnectTrigger();
    }

    return returnStatus;
}

void AWS_Init(void)
{
    MqttPublish_Init();
    xTaskCreate(aws_iot_client_main, "aws_iot_client_main", 8 * 1024, NULL, 10, NULL); //确认最小
}
void AWS_ConnectTrigger(void)
{
    if(wireless_state.station_state == connected)
    { //WIFI连接成功后，才能触发AWS IoT连接
        ESP_LOGE(TAG,"触发 AWS IoT初始化");
        xSemaphoreGive(sync_aws_creat);
    }
    else
    {
        ESP_LOGE(TAG,"WIFI 断开状态, 无法使用AWS IoT");
    }
}
